package com.serena.da.rest.services;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import com.serena.da.rest.http_helpers.Response;
import sun.misc.BASE64Encoder;


/**
 * Created by Spitkovskyi Igor on 7/24/2014.
 */
public class SraServiceClient {
    public static SraServiceClient s_client = null;

    private String host;
    private String port;
    private String user;
    private String pwd;

    /* Need to use client in multi-threading flow. Try information at http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html  ()
       Find section started with "While HttpClient instances are thread safe and can be shared between multiple threads of execution, it is highly recommended that each thread maintains its own dedicated instance of HttpContext"
       So, if I try using client as a singletone, I get exception.
    */
    //protected static CloseableHttpClient client;

    public CloseableHttpClient client;
    //PoolingHttpClientConnectionManager cm;
    BasicHttpClientConnectionManager simple_cm;

    protected SraServiceClient() {
        //client = HttpClients.createDefault();

        //client = HttpClientBuilder.create().build();

        //cm = new PoolingHttpClientConnectionManager();
        //client = HttpClients.custom().setConnectionManager(cm).build();
        simple_cm = new BasicHttpClientConnectionManager();
        client = HttpClients.custom().setConnectionManager(simple_cm).build();
    }

    protected SraServiceClient(String host, String port, String user, String pwd) {
        this();
        this.host = host;
        this.port = port;
        this.user = user;
        this.pwd = pwd;
    }

    public static SraServiceClient getInstance(String host, String port, String user, String pwd) {
        if (s_client == null) {
            s_client = new SraServiceClient(host, port, user, pwd);
        }

        if (!s_client.host.equals(host) || !s_client.port.equals(port) || !s_client.user.equals(user) || !s_client.pwd.equals(pwd)) {
            s_client = new SraServiceClient(host, port, user, pwd);
        }

        return s_client;
    }

    @Parameters({"host", "port", "user", "pwd"})
    @Test
    public void initClient(String host, String port, String user, String pwd) {
        getInstance(host, port, user, pwd);
    }

    public static SraServiceClient getInstance() throws Exception {
        if (s_client == null) {
            throw new Exception("There is no client initialized and required credentials [host, port, user, password] have not been provided to initialize it");
        }
        return s_client;
    }

    //This method should behave like "reopening" client. Haven't tried it, but it should work.
    public static SraServiceClient Reinitialize() throws Exception {
        if (s_client == null) {
            throw new Exception("There is no client initialized and required credentials [host, port, user, password] have not been provided to initialize it");
        }
        s_client.close(); //Close current client instance;
        s_client = new SraServiceClient(s_client.getHost(), s_client.getPort(), s_client.getUser(), s_client.getPassword());

        return s_client;
    }

    public String getHost() {
        return host;
    }

    public String getPort() {
        return port;
    }

    public String getUser() {
        return user;
    }

    public String getPassword() {
        return pwd;
    }

    //Generating Authorization header and attaching it to request
    protected void setAuthorizationHeader(HttpRequestBase req) {
        //Authorization
        byte[] encodedPassword = (this.user + ":" + this.pwd).getBytes();
        BASE64Encoder encoder = new BASE64Encoder();
        String USER_AUTH = encoder.encode(encodedPassword);
        req.setHeader(new BasicHeader("Authorization", "Basic " + USER_AUTH));
    }


    //Trying to send request and receive response from server
    protected Response sendRequest(HttpRequestBase request) throws Exception {
        //getRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36");
        setAuthorizationHeader(request);
        int statusCode = 0;
        String responseBody = "";

        CloseableHttpResponse response = client.execute(request);
        try {
            HttpEntity entity = response.getEntity();
            statusCode = response.getStatusLine().getStatusCode();
            responseBody = EntityUtils.toString(entity);
        } finally {
            response.close();
        }

        return new Response(statusCode, responseBody);
    }

    public void close() {
        try {
            client.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
